package com.lge.clock.timer;

import static com.lge.clock.util.CommonUtil.getDefaultRingToneInfo;

import java.io.IOException;

import android.app.Activity;
import android.app.Service;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.database.Cursor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.IBinder;
import android.os.Vibrator;
import android.provider.BaseColumns;

import android.provider.MediaStore;
import android.provider.Settings;
import android.util.Log;

import com.lge.clock.AlarmClockActivity;
import com.lge.clock.R;

import com.lge.clock.TimerFragment;
import com.lge.clock.util.CommonUtil;
import com.lge.clock.util.MediaInfoHolder;
import com.lge.clock.util.CommonUtil.AlarmDBQueryCondition;
import com.lge.clock.util.CommonUtil.OPERATOR;
import com.lge.clock.util.CommonUtil.PrefreParent;
import com.lge.clock.util.MediaInfoHolder.MediaLocation;

import com.lge.lgdrm.Drm;
import com.lge.lgdrm.DrmContentSession;
import com.lge.lgdrm.DrmManager;

import android.media.MediaMetadataRetriever;



/**
 * @author LGE Cappuccino
 */
public class TimerAlarm extends Service
{
	private MediaPlayer mMediaPlayer;
	private AudioManager mAudioManager;
	private Vibrator mVibrator;
	private static final int VIB_WAIT = 200, VIB_KEEP = 800;
	private final long[] vibratePatterns = new long[]{VIB_WAIT, VIB_KEEP};
	
	private String mTone;
	private ContentResolver mResolver;
	
	// private static final int DRM_INVALID      = 0;
	private static final int DRM_EXPIRED      = 1;
	private static final int DRM_CANNOTBEUSED = 1;
	private static final int DRM_VALID        = 2;
	
	/**
	 * Log
	 */
	private static final String TAG = "TimerAlarm";
	
	//ANDY_PORTING LGDRM [lg-drm@lge.com 100414]
    private boolean mDrmFile = false;
    private DrmContentSession mDrmSession = null; // Content session to reset keyinfo
    //ANDY_END
	
	// [mo2sangbong.lee@lge.com][20291] 2011.08.11. add timer alarm power off issue fix START		
	private static TimerAlarm mTimerAlarm = null;
	// [mo2sangbong.lee@lge.com][20291] 2011.08.11. add timer alarm power off issue fix END	    
	/**
	 * Method onCreate.
	 */
	@Override
	public void onCreate() {
		super.onCreate();
		// [mo2sangbong.lee@lge.com][20291] 2011.08.11. add timer alarm power off issue fix START		
		setTimerAlarm(this);
		// [mo2sangbong.lee@lge.com][20291] 2011.08.11. add timer alarm power off issue fix END			
		mMediaPlayer = new MediaPlayer();
		mVibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE);
		mAudioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
		//AlarmAlertWakeLock.acquireCpuWakeLock(this); //[hyunjung78.park][1427] 2011.10.13
		TimerWakeLock.acquireCpuWakeLock(this);//[hyunjung78.park][1427] 2011.10.13
	}
	
	/**
	 * Method onStartCommand.
	 * @param intent Intent
	 * @param flags int
	 * @param startId int
	 * @return int
	 */
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		if (intent == null) {
            stopSelf();
            return START_NOT_STICKY;
        }

		Boolean mVibration = (boolean)intent.getBooleanExtra("Vibration", true);
		String mRingtone = (String)intent.getStringExtra("Ringtone");
		
		if(mRingtone == null) {
			stopSelf();
			return START_NOT_STICKY;
		}
		
		wakeAlarm(mVibration, mRingtone);
		
		return START_STICKY;
	}


	/**
	 * Method onDestroy.
	 */
	@Override
	public void onDestroy() {
		
		// [mo2sangbong.lee@lge.com][20291] 2011.08.11. add timer alarm power off issue fix START		
		setTimerAlarm(null);
		// [mo2sangbong.lee@lge.com][20291] 2011.08.11. add timer alarm power off issue fix END		
		releaseAlarm();
		//AlarmAlertWakeLock.release(); //[hyunjung78.park][1427] 2011.10.13
		TimerWakeLock.release();//[hyunjung78.park][1427] 2011.10.13
	}

	// [mo2sangbong.lee@lge.com][20291] 2011.08.11. add timer alarm power off issue fix START	
	public void forceStop() {
		Log.e("TimerAlarm", "============ TimerAlarm force Stop =======> ");
		setTimerAlarm(null);
		releaseAlarm();
		//AlarmAlertWakeLock.release(); //[hyunjung78.park][1427] 2011.10.13
		TimerWakeLock.release(); //[hyunjung78.park][1427] 2011.10.13
	}
	// [mo2sangbong.lee@lge.com][20291] 2011.08.11. add timer alarm power off issue fix END	
	
	/**
	 * get right ring tone
	 * @param ringtone
	 * @return
	 */
	private String getRightRingtoneURI(String ringtone){
		String ret = "";
		AlarmDBQueryCondition queryCtn = CommonUtil.getBuildOperator() == OPERATOR.DCM  ? AlarmDBQueryCondition.NO_CONDITION : AlarmDBQueryCondition.SET_ALARM;
		MediaInfoHolder infoHolder = CommonUtil.getFinededDefaultTone(getApplicationContext(), ringtone, queryCtn, PrefreParent.TIMER);
		if(infoHolder.mediaLocation == MediaLocation.NO_WHERE){
			
			/*find default ring tone*/
			MediaInfoHolder defaultHolder = getDefaultRingToneInfo(getApplicationContext(), queryCtn);
			if(defaultHolder.mediaURI != null){
				ret = defaultHolder.mediaURI.toString();
			}else{
				Log.d("suein", "getDefaultRingToneInfo : "+defaultHolder);
			} //End Of if
			
		}else{
			ret = infoHolder.mediaURI != null ? infoHolder.mediaURI.toString() : "";
		}//End Of if
		
		return ret;
	} //End Of Method
	
	/**
	 * Method wakeAlarm.
	
	 * @param isVib boolean
	 * @param ringtone String
	 */
	public void wakeAlarm(boolean isVib, String ringtone) {
		if(isVib) {
			mVibrator.vibrate(vibratePatterns, 0);
		}
		
		try {
			if ( !"Off".equalsIgnoreCase(ringtone) ) {
	            //ANDY_PORTING LGDRM [lg-drm@lge.com 100414]
	            int status = 0;
	            String path = null;
	            if (Drm.LGDRM) {
	                path = getActualRingtoneUri(this, Uri.parse(ringtone));
	                if (path != null) {
	                   status = checkDRM(path);
	                }
	            }
	            if (status == DRM_CANNOTBEUSED) {
	                // Can't be used as ringtone, ring default
	                // TODO: Need to define default persistent alarm sound
	                setDataSourceFromResource(getResources(), mMediaPlayer, com.lge.clock.R.raw.fallbackring);
	                
	            } else if (status == DRM_VALID) {
	                mMediaPlayer.setDataSource(path);
	                
	            } else {
	            	String toneUri = getRightRingtoneURI(ringtone);
	            	if(!toneUri.equals("")){
	            		mMediaPlayer.setDataSource(this, Uri.parse(toneUri));
	            	}else{
	            		mMediaPlayer = null;
	            	} //End Of if
	            	
	            }
	            
	            if ( mMediaPlayer != null ) {
	            	mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
			    	mMediaPlayer.setLooping(true);
			    	/*[START] 2012.06.01 suein1209.kim fixed that Alarm sounds and the sound of Timer has a different*/
//			    	mMediaPlayer.setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM), mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM));
			    	/*[END] 2012.06.01 suein1209.kim fixed that Alarm sounds and the sound of Timer has a different*/
					mMediaPlayer.prepare();
	            }
			}
		}
		catch (IllegalArgumentException e1) { 
			e1.printStackTrace();
		} 
		catch (SecurityException e1) {
			e1.printStackTrace();
		}
		catch (IllegalStateException e1) {
			e1.printStackTrace();
		}
		catch (IOException e1) {
			e1.printStackTrace();
			
			try {
				defaultTone();
			} catch (Exception e) {
				Log.e(TAG, "Excaption TimerAlarm -> defaultTone : "+e.getMessage());
				mMediaPlayer = null;
			} //End Of try
			
		}
		
		if ( mMediaPlayer != null )
			mMediaPlayer.start();
	}
	
    //ANDY_PORTING LGDRM [lg-drm@lge.com 100414]
    /*
        0 : Not DRM
        1 : Rights expired or can't be used as ringtone
        2 : Valid Rights exist for ringtone
    */
    private int checkDRM(String filename) {
        mDrmFile = false;
        mDrmSession = null;

        if (filename == null) {
            return 0;
        }

        int length = filename.length();
        if (false == (filename.regionMatches(true, length - 3, ".dm", 0, 3)
         || filename.regionMatches(true, length - 4, ".dcf", 0, 4)
         || filename.regionMatches(true, length - 4, ".odf", 0, 4)
         || filename.regionMatches(true, length - 4, ".o4a", 0, 4)
         || filename.regionMatches(true, length - 4, ".o4v", 0, 4))) {
            return 0; // Normal file
        }


        try {
        	int drmType = DrmManager.isDRM(filename);
            
            if (drmType < Drm.CONTENT_TYPE_DM || drmType > Drm.CONTENT_TYPE_DCFV2) {
                return 0; // Normal file or not wrapped format
            }
        } catch ( NullPointerException e ) {
        	e.printStackTrace();
        }
        

        try {
            DrmContentSession session = DrmManager.createContentSession(filename, this);
            
            /*
			 * [START] 2012.02.10 suein1209.kim INTERNAL_TEST.WBT_12 - Defect #308151
			 */
			if (session == null)
				return 1; // may be default
			/*
			 * [END] 2012.02.10 suein1209.kim INTERNAL_TEST.WBT_12 - Defect #308151
			 */
            
            boolean bIsActionSupported = session.isActionSupported(Drm.CONTENT_ACT_RINGTONE);
            if ( false == bIsActionSupported ) {
                return DRM_EXPIRED; // Expired
            }

            int nDescInfo = session.setDecryptionInfo(false);
            if ( Drm.ERR_SUCCESS != nDescInfo ) {
                return DRM_CANNOTBEUSED; // Failed to set key info
            }
            
            // consume right
            session.consumeRight(session.getDrmTime(), 0);

            mDrmFile = true;
            mDrmSession = session;
            return DRM_VALID;
        } catch (Exception e) {
        	e.printStackTrace();
        }

        return 1;
    }    
    /**
     * Gets a actual path for the given ringtone {@link Uri}.
     * 
     * @param ringtoneUri Ringtone uri to resolve.
     * @return A data path of given {@link Uri}.
     */
    private String getActualRingtoneUri(Context context, Uri ringtoneUri) {
        if (context == null || ringtoneUri == null) {
            return null;
        }
        String scheme = ringtoneUri.getScheme();
        if (scheme == null || scheme.equals("file")) {
            return ringtoneUri.getPath();
        }
        String authority = ringtoneUri.getAuthority();
        if (Settings.AUTHORITY.equals(authority)) {
            Uri uri = RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.getDefaultType(ringtoneUri));
            if (uri == null) {
                return null;
            }
            return getActualRingtoneUri(context, uri);
        } else if (MediaStore.AUTHORITY.equals(authority)) {
            Cursor cursor = null;
            String data = null;
            try {
            	cursor = context.getContentResolver().query(ringtoneUri, new String[]{MediaStore.MediaColumns.DATA}, null, null, null);
                if (cursor != null && cursor.getCount() == 1) {
                    cursor.moveToFirst();
                    data = cursor.getString(0);
                }
            } catch( Exception e ) {
            	e.printStackTrace();
            } finally {
            	if (cursor != null) {
                    cursor.close();
                }
            }

            return data;
        }
        
        return null;
    }
    //ANDY_END
    
    private void setDataSourceFromResource(Resources resources, MediaPlayer player, int res) throws java.io.IOException {
    	AssetFileDescriptor afd = resources.openRawResourceFd(res);

    	try {
    		if (afd != null) {
                player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
            }
        } catch( Exception e) {
        	e.printStackTrace();
        } finally {
        	if( afd != null )
        		afd.close();
        }
    }
    
    /*private static final String[] INTERNAL_COLUMNS = new String[] {
		     MediaStore.Audio.Media._ID,
		     MediaStore.Audio.Media.TITLE,
		     "\"" + MediaStore.Audio.Media.INTERNAL_CONTENT_URI + "\"",
		     MediaStore.Audio.Media.TITLE_KEY
	};*/
    
    private static final String[] INTERNAL_COLUMNS = new String[] {
    		BaseColumns._ID,
    		MediaStore.MediaColumns.TITLE,
    		"\"" + MediaStore.Audio.Media.INTERNAL_CONTENT_URI + "\"",
    		MediaStore.Audio.AudioColumns.TITLE_KEY
    };
    
	private void defaultTone() throws NullPointerException{
    	Uri alert = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM);
	    if (alert == null) {
	    	mTone = "Off";
        	return; 
	    } else { 
	    	int i = 1;
            boolean tag = false;
            String defaulttone = "";
            mResolver = this.getContentResolver();
	    	Cursor cur = mResolver.query(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, INTERNAL_COLUMNS,
    						               			"is_alarm = 1",  null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);            
    	 	try {
    	 		if ( cur != null && cur.moveToFirst() ) {
    	 			do {
        	 			// Get the field values     
        	            Uri uri1 = ContentUris.withAppendedId(Uri.parse(cur.getString(2)), cur.getLong(0));
        	            if (uri1.toString().equalsIgnoreCase(alert.toString())) {
        	            	mTone =	uri1.toString();
//        	            	TimerFragment.saveTonePreferences(uri1.toString());
        	             	
        	            	tag = true;
    	    	            break;
        	            }
        	              
        	            if (i == 4) {
        	            	defaulttone = uri1.toString();
        	            }
        	            i++;
        	 		} while (cur.moveToNext());
        	 	}
    	 	} catch (Exception e) {
    	 		e.printStackTrace();
    	 	} finally {
    	 		if (cur != null)
    	 			cur.close();
    	 	}
    	 	        
			if (tag == false) { 
				mTone =	defaulttone;
//				TimerFragment.saveTonePreferences(defaulttone);
			}
	    }
	    
	    try {
	    	if ( mMediaPlayer != null ) {
	    		mMediaPlayer.setDataSource(this, Uri.parse(mTone)) ;
				mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
		    	mMediaPlayer.setLooping(true);

		    	/*[START] 2012.06.01 suein1209.kim fixed that Alarm sounds and the sound of Timer has a different*/
				//OPEN_CN_LUNAR shengjie.shi@lge.com 2012-04-06 fixed bug about when the phone is vibration, the default ringtone didn't ring[START]
//		    	mMediaPlayer.setVolume(mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM), mAudioManager.getStreamVolume(AudioManager.STREAM_ALARM));
				//OPEN_CN_LUNAR shengjie.shi@lge.com 2012-04-06 fixed bug about when the phone is vibration, the default ringtone didn't ring[END]
		    	/*[END] 2012.06.01 suein1209.kim fixed that Alarm sounds and the sound of Timer has a different*/
				mMediaPlayer.prepare();
				mMediaPlayer.start();
	    	}
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void releaseAlarm() {
		if(mVibrator != null) {
			mVibrator.cancel();
		}
		
		if (mMediaPlayer != null) {
			
//			mMediaPlayer.seekTo(mMediaPlayer.getDuration());
			mMediaPlayer.stop();
			mMediaPlayer.release();
			mMediaPlayer = null;
            //ANDY_PORTING LGDRM [lg-drm@lge.com 100414]
            if ( mDrmFile && mDrmSession != null) {
                // Reset used key
                mDrmSession.setDecryptionInfo(true);
                mDrmFile = false;
                mDrmSession = null;
            }
            //ANDY_END
		}
	}

	/**
	 * Method onBind.
	 * @param arg0 Intent
	 * @return IBinder
	 */
	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}
	
	private static void setTimerAlarm(TimerAlarm timerAlarm) {
		mTimerAlarm = timerAlarm;
	}
	
	public static TimerAlarm getTimerAlarm() {
		return mTimerAlarm;
	}
}